package com.example.socketchat.server;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.example.socketchat.handler.ChatServerHandler;

import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import io.netty.handler.codec.LengthFieldPrepender;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.timeout.IdleStateHandler;
import io.netty.util.CharsetUtil;

import java.util.concurrent.TimeUnit;
import lombok.extern.slf4j.Slf4j;

/**
 * Socket服务器通道初始化器
 * 
 * 负责配置每个新连接的通道管道，添加各种编解码器和处理器
 */
@Slf4j
@Component
public class ChatServerInitializer extends ChannelInitializer<SocketChannel> {

    @Autowired
    private ChatServerHandler chatServerHandler;

    @Override
    protected void initChannel(SocketChannel ch) throws Exception {
        ChannelPipeline pipeline = ch.pipeline();
        
        log.debug("初始化新连接的channel: {}", ch.remoteAddress());
        
        // 添加日志处理器
        pipeline.addLast(new LoggingHandler(LogLevel.DEBUG));
        
        // 添加帧解码器，处理TCP粘包/拆包问题
        // 最大帧长度为64KB，长度字段偏移为0，长度字段长度为4字节，长度调整值为0，跳过的初始字节数为4
        pipeline.addLast(new LengthFieldBasedFrameDecoder(65536, 0, 4, 0, 4));
        
        // 添加帧编码器，在消息前面添加长度字段
        pipeline.addLast(new LengthFieldPrepender(4));
        
        // 添加字符串编解码器，将字节转换为字符串，使用UTF-8编码
        pipeline.addLast(new StringDecoder(CharsetUtil.UTF_8));
        pipeline.addLast(new StringEncoder(CharsetUtil.UTF_8));
        
        // 添加心跳检测处理器
        // 读空闲时间60秒，写空闲时间30秒，读写空闲时间0秒
        pipeline.addLast(new IdleStateHandler(60, 30, 0, TimeUnit.SECONDS));
        
        // 添加业务逻辑处理器
        pipeline.addLast(chatServerHandler);
        
        log.debug("channel初始化完成: {}", ch.remoteAddress());
    }
} 